/** ###################################################################
**     Filename  : ProcessorExpert.c
**     Project   : ProcessorExpert
**     Processor : MK40X256VMD100
**     Version   : Driver 01.00
**     Compiler  : CodeWarrior ARM C Compiler
**     Date/Time : 2011-03-25, 14:51, # CodeGen: 0
**     Abstract  :
**         Main module.
**         This module contains user's application code.
**     Settings  :
**     Contents  :
**         No public methods
**
** ###################################################################*/
/* MODULE ProcessorExpert */


/* Including needed modules to compile this module/procedure */
#include "Cpu.h"
#include "Events.h"
#include "SegLCD1.h"
#include "Buzzer.h"
#include "Counter.h"
#include "TSI1.h"
#include "Debounce.h"
/* Including shared modules, which are used for whole project */
#include "PE_Types.h"
#include "PE_Error.h"
#include "PE_Const.h"
#include "IO_Map.h"

#include "KwikStik_SegLCD.h"

/* Initial text displayed during application restart */
const char IntroText[] = "STOPWATCH DEMO";

/* Time conversion macros */
#define GetHours(TimeMS) ((uint32_t)(TimeMS / 3600000UL) % 24UL)
#define GetMinutes(TimeMS) ((uint32_t)(TimeMS / 60000UL) % 60UL)
#define GetSeconds(TimeMS) ((uint32_t)(TimeMS / 1000UL) % 60UL)
#define GetMilliseconds(TimeMS) ((uint32_t)((TimeMS / 10) % 100UL))

/* Touch button constants */
#define START_STOP_BUTTON (0U)  /* Left top KwikStik touch sense button */
#define RESET_BUTTON      (1U)  /* Right top KwikStik touch sense button */

/* Stopwatch machine states */
typedef enum {RUN, STOP, INTRO, HELP} TAppState;

LDD_TDeviceData *lcdDev;
LDD_TDeviceData *ConsoleUART_DeviceData;
LDD_TDeviceData *buzzerDev;
LDD_TDeviceData *tsiDev;
LDD_TDeviceData *debounceDev;
LDD_TDeviceData *counterDev;

volatile TAppState AppState; 
char     ElapsedTimeStr[20];
volatile uint32_t ElapsedTimeMs = 0;
volatile uint16_t buzzerCnt;

/* This value determines how many cycles takes the TSI counter average value measurement */
#define CALIBRATION_LENGTH 100

/* This value determines the TSI sensitivity/robustness. It expresses the amplitude of threshold level in
   percentage of average counter value. Suitable range is 5-90. Smaller value means higher sensitivity.
   Note that this % of average value can't be smaller than average range of TSI counter. */
#define TSI_SENSITIVITY 8

void SetTSIThresholds(void)
{
	uint32_t calibCounter;
	uint32_t i;
	uint32_t pin0max, pin0min, pin0mid;
	uint32_t pin5max, pin5min, pin5mid;
	TSI1_LDD_TSI_TData cntrArray[16];

	pin0min = 0xFFFF;
	pin0max = 0x0;
	pin5min = 0xFFFF;
	pin5max = 0x0;

	for (calibCounter = 0; calibCounter < CALIBRATION_LENGTH; calibCounter++)
	{
		/* Start measurement */
		TSI1_TriggerSoftwareScan(tsiDev);

		do {
			/* Measurement Running */
		} while (TSI1_GetScanStatus(tsiDev));

		/* Workaround for errata ID 2638 */
		for(i = 0; i < 500u; i++) /* Delay */
		{
			asm ("NOP"); 
		}

		TSI1_GetCounterArray(tsiDev, cntrArray);
		if (cntrArray[0] != 0 && cntrArray[0] != 0xFFFF)
		{
			if (pin0max < cntrArray[0]) pin0max = cntrArray[0];
			if (pin5max < cntrArray[5]) pin5max = cntrArray[5];
		}
		if (cntrArray[5] != 0 && cntrArray[5] != 0xFFFF)
		{
			if (cntrArray[0] < pin0min) pin0min = cntrArray[0];
			if (cntrArray[5] < pin5min) pin5min = cntrArray[5];
		}
		TSI_PDD_Clear_StatusFlags(TSI0_BASE_PTR, 0xFFFFFFFFu);   
	}

	pin0mid = (pin0min + pin0max)/2;
	pin5mid = (pin5min + pin5max)/2;

	TSI1_Disable(tsiDev);
	TSI1_SetLowThreshold(tsiDev, 
			(TSI1_LDD_TSI_TThresholdValue) pin0mid - (pin0mid/100)*TSI_SENSITIVITY, 
			LDD_TSI_PIN_0_INDEX);
	TSI1_SetHighThreshold(tsiDev, 
			(TSI1_LDD_TSI_TThresholdValue) pin0mid + (pin0mid/100)*TSI_SENSITIVITY, 
			LDD_TSI_PIN_0_INDEX);

	TSI1_SetLowThreshold(tsiDev, 
			(TSI1_LDD_TSI_TThresholdValue) pin5mid - (pin5mid/100)*TSI_SENSITIVITY, 
			LDD_TSI_PIN_5_INDEX);
	TSI1_SetHighThreshold(tsiDev, 
			(TSI1_LDD_TSI_TThresholdValue) pin5mid + (pin5mid/100)*TSI_SENSITIVITY, 
			LDD_TSI_PIN_5_INDEX);               
	TSI1_Enable(tsiDev);  
}

/*
** ===================================================================
** Generate pulse with period 
** ===================================================================
*/
void beep(uint16_t count){
	if (count > 0) {
		buzzerCnt = count;
		Buzzer_Enable(buzzerDev);
	}
}

/*
** ===================================================================
** Handling of Touch buttons 
** ===================================================================
*/
void OnButtonPressed(uint8_t Index) {
  if (AppState == INTRO) {
    /* Do nothing when into text is displayed */
  } else if (AppState == HELP) {
    AppState = STOP;
	} else {
		switch(Index) {
			/* Start/Stop button (TSI - E1) */
			case START_STOP_BUTTON:
				if (AppState == RUN) {
					/* Stop stopwatch */
					AppState = STOP;
					Counter_Disable(counterDev);
					lcd_SetGraphSegment(lcdDev, LCD_GRPH_SEG_CLOCK, FALSE);
				} else {
					/* Start stopwatch */
					AppState = RUN;
					lcd_SetGraphSegment(lcdDev, LCD_GRPH_SEG_CLOCK, TRUE);
					Counter_Enable(counterDev);
				}
				beep(100);  
				break;
			/* Reset button (TSI - E2) */
			case RESET_BUTTON:
				ElapsedTimeMs = 0;
				beep(500);  
				break;
			default:
				/*Do nothing*/
				break;
		}
	}
}

/*
** ===================================================================
** Displays intro text and control buttons functions.  
** ===================================================================
*/
void PlayIntro(void)
{
	int8_t   tmp = -1;
	int16_t  i;
	uint32_t j = 0;

	Counter_Enable(counterDev);
	/* Display intro text */
	for (i = 36; i >= (-1 * (strlen(IntroText) * 6)); i--) {
		while ((ElapsedTimeMs - j) < 50) {}
		j = ElapsedTimeMs;
		lcd_DisplayString(lcdDev, i, (char *)IntroText);
	}  
	tmp = -1;
	/* Display control buttons functions until E1 or E2 key is pressed */
	AppState = HELP;
	while (AppState == HELP) {
		if ((GetSeconds(ElapsedTimeMs) % 3) != tmp) {
			tmp = GetSeconds(ElapsedTimeMs) % 3;
			lcd_ClearScreen(lcdDev);
			switch (tmp) {
				case 0: lcd_DisplayChar(lcdDev, 0, '~');
					lcd_DisplayString(lcdDev, 5, "Start"); 
					break;
				case 1: lcd_DisplayChar(lcdDev, 0, '~');
					lcd_DisplayString(lcdDev, 5, "STOP "); 
					break;
				case 2: lcd_DisplayChar(lcdDev, 33, '~');
					lcd_DisplayString(lcdDev, 3, "RESET"); 
					break;
			}
		}	  
	}  
	Counter_Disable(counterDev);
}


void main(void)
{
  /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
  PE_low_level_init();
  /*** End of Processor Expert internal initialization.                    ***/

  AppState = INTRO;

  /* Drivers initialization */
  counterDev = Counter_Init( NULL );
  lcdDev = SegLCD1_Init( NULL );
  buzzerDev = Buzzer_Init(NULL);
  tsiDev = TSI1_Init(NULL);
  debounceDev = Debounce_Init(NULL);

  /* Calibrate TSI thresholds (enable touch sensing functionality) */
  SetTSIThresholds();

  /* Display FSL logo and clock icon */
  lcd_SetGraphSegment(lcdDev, LCD_GRPH_SEG_CLOCK, FALSE);
  lcd_SetGraphSegment(lcdDev, LCD_GRPH_FSL_LOGO, TRUE);

  /* Display intro text and help screen */
  beep(500);
  PlayIntro();
  beep(500);

  ElapsedTimeMs = 0;
  lcd_ClearScreen(lcdDev);

  for(;;)
  {
	  /* Convert elapsed time into a string in format MM:SS.HS */
	  sprintf( (char *)ElapsedTimeStr,"%02d:%02d.%02d",
			  GetMinutes(ElapsedTimeMs),
			  GetSeconds(ElapsedTimeMs),
			  GetMilliseconds(ElapsedTimeMs)
	  );
	  /* Display elapsed time on segment LCD */
	  lcd_DisplayString(lcdDev, 4, ElapsedTimeStr);
  }
	  
  /*** Don't write any code pass this line, or it will be deleted during code generation. ***/
  /*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/
  #ifdef PEX_RTOS_START
    PEX_RTOS_START();                  /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
  #endif
  /*** End of RTOS startup code.  ***/
  /*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
  for(;;){}
  /*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/

/* END ProcessorExpert */
/*
** ###################################################################
**
**     This file was created by Processor Expert 0.00.00 [04.48]
**     for the Freescale Kinetis series of microcontrollers.
**
** ###################################################################
*/
